package com.virtualparadigm.identity;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import com.virtualparadigm.hierarchy.LineageList;

public class ResourceAddressParser implements Serializable
{
	private static final long serialVersionUID = 1L;
//	public static final String SCHEME_DELIMITER = "://";
	public static final String NAMESPACE_DELIMITER = ".";
	public static final String PATH_DELIMITER = "/";
	public static final String PARAMETER_DELIMITER = "&";
	
	public static ResourceAddressParts getResourceAddressParts(String resourceAddress)
	{
		ResourceAddressParts resourceAddressParts = null;
		if(resourceAddress != null)
		{
			try
			{
				URI uri = new URI(resourceAddress);
				String p = uri.getQuery();
				resourceAddressParts = 
						new ResourceAddressParts(
								uri.getScheme(), 
								uri.getAuthority(), 
								uri.getPath(), 
								ResourceAddressParser.parseURIQuery(uri.getQuery()));
			}
			catch(URISyntaxException urise)
			{
				urise.printStackTrace();
			}
		}
		return resourceAddressParts;
	}
	
	public static ResourceAddressParts getResourceAddressParts(String scheme, LineageList<ResourcePathElement> resourcePathElements)
	{
		ResourceAddressParts resourceAddressParts = null;
		if(resourcePathElements != null)
		{
			StringBuffer namespaceBuffer = new StringBuffer();
			StringBuffer pathBuffer = new StringBuffer();
			ResourcePathElement resourcePathElement = null;
			for(Iterator<ResourcePathElement> it=resourcePathElements.getParentsFirstIterator(); it.hasNext(); )
			{
				resourcePathElement = it.next();
				pathBuffer.append(resourcePathElement.getValuesString() + PATH_DELIMITER);
				namespaceBuffer.insert(0, resourcePathElement.getName() + NAMESPACE_DELIMITER);
			}
			resourceAddressParts = 
					new ResourceAddressParts(
							scheme, 
							namespaceBuffer.substring(0, namespaceBuffer.length()-1), 
							pathBuffer.substring(0, pathBuffer.length()-1), 
							null);
		}
		return resourceAddressParts;
	}
	
	public static LineageList<ResourcePathElement> getResourcePathElements(ResourceAddressParts resourceAddressParts)
	{
		LineageList<ResourcePathElement> resourcePathElements = null;
		if(resourceAddressParts != null && resourceAddressParts.getNamespace() != null && resourceAddressParts.getPath() != null)
		{
			resourcePathElements = new LineageList<ResourcePathElement>();
			String[] namespaceTokens = resourceAddressParts.getNamespace().split("\\" + NAMESPACE_DELIMITER);
			String[] pathTokens = resourceAddressParts.getPath().split(PATH_DELIMITER);
			if(namespaceTokens != null && pathTokens != null && namespaceTokens.length == pathTokens.length)
			{
				int namespaceIndex = namespaceTokens.length-1;
				for(int pathIndex=0; pathIndex<pathTokens.length; pathIndex++)
				{
System.out.println("pathIndex=" + pathIndex);					
					resourcePathElements.queueChild(new ResourcePathElement(namespaceTokens[namespaceIndex], pathTokens[pathIndex]));
					namespaceIndex--;
				}
			}
		}
		return resourcePathElements;
	}
	
	public static URI getResourceURI(ResourceAddressParts resourceAddressParts)
	{
		URI uri = null;
		if(resourceAddressParts != null && resourceAddressParts.getScheme() != null && resourceAddressParts.getNamespace() != null)
		{
			try
			{
				uri = 
						new URI(
								resourceAddressParts.getScheme(), 
								resourceAddressParts.getNamespace(), 
								PATH_DELIMITER + resourceAddressParts.getPath(), 
								ResourceAddressParser.buildURIQuery(resourceAddressParts.getParameters()), 
								null);
			}
			catch(URISyntaxException urise)
			{
				urise.printStackTrace();
			}
		}
		return uri;
	}
	
	public static URI getResourceURI(String scheme, LineageList<ResourcePathElement> resourcePathElements, Properties parameters)
	{
		URI uri = null;
		if(scheme != null && resourcePathElements != null)
		{
			ResourceAddressParts resourceAddressParts = ResourceAddressParser.getResourceAddressParts(scheme, resourcePathElements);
			if(resourceAddressParts != null)
			{
				resourceAddressParts.setScheme(scheme);
				resourceAddressParts.setParameters(parameters);
				uri = ResourceAddressParser.getResourceURI(resourceAddressParts);
			}
		}
		return uri;
	}
	
	public static LineageList<ResourcePathElement> getResourcePathElementLineageList(String namespace, String path)
	{
		LineageList<ResourcePathElement> lineageList = null;
		
		namespace = ResourceAddressParser.trimDelimiters(namespace, NAMESPACE_DELIMITER);
		path = ResourceAddressParser.trimDelimiters(path, PATH_DELIMITER);
		
		if(namespace != null && path != null)
		{
			String[] namespaceTokens = namespace.split("\\" + NAMESPACE_DELIMITER);
			String[] pathTokens = path.split(PATH_DELIMITER);
			if(namespaceTokens != null && pathTokens != null && namespaceTokens.length == pathTokens.length)
			{
				lineageList = new LineageList<ResourcePathElement>();
				int namespaceIndex = namespaceTokens.length - 1;
				for(int pathIndex=0; pathIndex<pathTokens.length; pathIndex++)
				{
					lineageList.queueChild(new ResourcePathElement(namespaceTokens[namespaceIndex], pathTokens[pathIndex]));
					namespaceIndex--;
				}
			}
		}
		return lineageList;
	}
	
	public static String trimDelimiters(String str, String delimiter)
	{
		String retValue = null;
		if(str != null && delimiter != null)
		{
			retValue = str.replaceAll("^\\" + delimiter + "+", "").replaceAll("\\" + delimiter + "+$", "");
		}
		return retValue;
	}
	
	// =============================================================
	// UTILITY METHODS
	// =============================================================
	public static String buildURIQuery(Properties properties)
	{
		StringBuffer sb = new StringBuffer();
		if(properties != null)
		{
			Iterator<String> it = properties.stringPropertyNames().iterator();
			String key = null;
			if(it.hasNext())
			{
				key = it.next();
				sb.append(key + "=" + properties.getProperty(key));
			}
			while(it.hasNext())
			{
				key = it.next();
				sb.append("&" + key + "=" + properties.getProperty(key));
			}
		}
		return (sb.length() > 0) ? sb.toString() : null;
	}
	
	public static Properties parseURIQuery(String query)
	{
		Properties properties = null;
		if(query != null)
		{
			properties = new Properties();
			String[] nameAndValue = null;
			try
			{
				for(String token : query.split("&"))
				{
					nameAndValue = token.split("=", 2);
					properties.put(
							URLDecoder.decode(nameAndValue[0], "UTF-8"), 
							URLDecoder.decode(nameAndValue[1], "UTF-8"));
				}
			}
			catch(UnsupportedEncodingException uee)
			{
uee.printStackTrace();
			}
		}
		return properties;
	}
	
	
	public static void main(String[] args)
	{
		
		ResourceAddressParts resourceAddressParts1 = ResourceAddressParser.getResourceAddressParts("http://bar.foo.com/c1/f_1/b1?p1=a&p2=b");
		System.out.println(resourceAddressParts1);
		
		
		
		LineageList<ResourcePathElement> resourcePathElements1 = new LineageList<ResourcePathElement>();

		List<String> comValueList = new ArrayList<String>();
		comValueList.add("c1");
		resourcePathElements1.queueChild(new ResourcePathElement("com", comValueList));
		
		List<String> fooValueList = new ArrayList<String>();
		fooValueList.add("f1");
		fooValueList.add("f2");
		resourcePathElements1.queueChild(new ResourcePathElement("foo", fooValueList));
		
		List<String> barValueList = new ArrayList<String>();
		barValueList.add("b1");
		resourcePathElements1.queueChild(new ResourcePathElement("bar", barValueList));
		
		ResourceAddressParts resourceAddressParts2 = ResourceAddressParser.getResourceAddressParts("resourceidentifier", resourcePathElements1);
		System.out.println(resourceAddressParts2);
		
		
		
		LineageList<ResourcePathElement> resourcePathElements2 = ResourceAddressParser.getResourcePathElements(resourceAddressParts2);
		System.out.println(resourcePathElements2);
		

		Properties params = new Properties();
		params.put("p1", "a");
		params.put("p2", "b");
		URI uri = ResourceAddressParser.getResourceURI(resourceAddressParts2);
		System.out.println(uri);

		
		
	}
	
}